package com.demo.microblockchain;

import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 创建一个钱包类来保存公钥和私钥
 * 公钥和私钥究竟是起到什么作用呢，其实公钥的作用就是地址，你可以分享你的公钥给别人以此来获取付款，而你的私钥的作用是为了对交易进行签名，这样其他人就不可以花费你的金额除非它拥有你的私钥，
 * 所以对于每个人而言我们必须保护好我们的私钥，不能透露我们的私钥信息给其他人。同时在我们进行交易的时候我们也会同时发送我们的公钥由此来验证我们的签名是有效的而且没有数据被篡改。
 * @author zlf
 * @email i@merryyou.cn
 * @since 1.0
 */
public class Wallet {

    public PrivateKey privateKey;
    public PublicKey publicKey;

    //该钱包所有的"未花费输出"，这个结构和事务中的其实是一样的，只不过这里多了一个未花费的条件约束，相当于净值，每当需要对别人进行转账的时候，可以直接到属于自己的未花费输出中去搜索指定，如果想知道自己的地址下共有多少余额，也可以通过未花费输出来获取
    //总之，这个就是为了方便获取某个地址下的可用输出。
    public HashMap<String,TransactionOutput> UTXOs = new HashMap<String,TransactionOutput>();

    public Wallet() {
        generateKeyPair();
    }

    public void generateKeyPair() {
        try {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDSA","BC");
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
            ECGenParameterSpec ecSpec = new ECGenParameterSpec("prime192v1");
            // Initialize the key generator and generate a KeyPair
            keyGen.initialize(ecSpec, random); //256
            KeyPair keyPair = keyGen.generateKeyPair();
            // Set the public and private keys from the keyPair
            privateKey = keyPair.getPrivate();
            publicKey = keyPair.getPublic();

        }catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    public float getBalance() {
        float total = 0;
        for (Map.Entry<String, TransactionOutput> item: NoobChain.UTXOs.entrySet()){
            TransactionOutput UTXO = item.getValue();
            if(UTXO.isMine(publicKey)) { //if output belongs to me ( if coins belong to me )
                UTXOs.put(UTXO.id,UTXO); //add it to our list of unspent transactions.
                total += UTXO.value ;
            }
        }
        return total;
    }

    public Transaction sendFunds(PublicKey _recipient,float value ) {
        if(getBalance() < value) {
            System.out.println("#Not Enough funds to send transaction. Transaction Discarded.");
            return null;
        }
        ArrayList<TransactionInput> inputs = new ArrayList<TransactionInput>();

        float total = 0;
        //当钱包里的未花费输出够了要转出的金额后，就可以了，这些未花费输出就是这笔交易的输入，可能是多笔未花费输出
        for (Map.Entry<String, TransactionOutput> item: UTXOs.entrySet()){
            TransactionOutput UTXO = item.getValue();
            total += UTXO.value;
            inputs.add(new TransactionInput(UTXO.id));
            if(total > value) break;
        }

        Transaction newTransaction = new Transaction(publicKey, _recipient , value, inputs);
        newTransaction.generateSignature(privateKey);

        //这笔交易的输入要从钱包的未花费输出里删除
        for(TransactionInput input: inputs){
            UTXOs.remove(input.transactionOutputId);
        }

        return newTransaction;
    }

	@Override
	public String toString() {
		return "Wallet [privateKey=" + privateKey.getClass().getSimpleName() + ", publicKey=" + publicKey.getClass().getSimpleName()
				+ ", UTXOs=" + UTXOs + "]";
	}

}